#include "GLWidget.h"
#include "ControlBar.h"
#include "GLRenderComp.h"
#include "RenderController.h"
#include "ScaleBar.h"
#include <QTime>
#include <QWheelEvent>
GLWidget::GLWidget(QWidget* parent)
	: Super(parent)
{
	setFormat(getGLFormat());
	setFocusPolicy(Qt::ClickFocus);
}
GLWidget::~GLWidget()
{
	makeCurrent();
	{
		gController->unInit();
#ifdef DEBUG_GL
		safeDelete(mLogger);
#endif
	}
	doneCurrent();
}

void GLWidget::initializeGL()
{
	initializeOpenGLFunctions();

	qDebug() << "GLWidget::initializeGL()";
#ifdef DEBUG_GL
	mLogger = new QOpenGLDebugLogger(this);
	connect(mLogger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage& debugMessage) {
		qDebug() << debugMessage.id() << debugMessage.message();
	});
	mLogger->initialize();
	mLogger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
#endif

	{
		mScaleBar = new ScaleBar(this);
		auto x	  = (width() - mScaleBar->width()) - 10;
		auto y	  = height() - mScaleBar->height() - 4;
		mScaleBar->move(x, y);

		connect(mScaleBar, &ScaleBar::signalAdd, this, &GLWidget::doScaleAdd);
		connect(mScaleBar, &ScaleBar::signalDec, this, &GLWidget::doScaleDec);
	}
	{
		mControlBar = new ControlBar(this);
		auto x		= 10;
		auto y		= height() - mControlBar->height() - 4;
		mControlBar->move(x, y);

		connect(mControlBar, &ControlBar::signalOk, this, &GLWidget::doControlCount);
	}
	gController->setMakeCurrentCall([this]() { this->makeCurrent(); });
	gController->setDoneCurrentCall([this]() { this->doneCurrent(); });
	gController->setRenderRequestCall([this]() { this->update(); });
	gController->setViewSize(size(), false);
	gController->init(size());

	mTimer = startTimer(1000 / 60);
}
void GLWidget::resizeGL(int w, int h)
{
	glViewport(0, 0, w, h);
	Super::resizeGL(w, h);
}
void GLWidget::paintGL()
{
	gController->paint();
	calcFPS();
	showFPS();
}

void GLWidget::resizeEvent(QResizeEvent* event)
{
	Super::resizeEvent(event);
	makeCurrent();
	{
		gController->setViewSize(size());
	}
	doneCurrent();
}
void GLWidget::wheelEvent(QWheelEvent* event)
{
	if (event->angleDelta().y() > 0)
	{
		doScaleAdd();
	}
	else if (event->angleDelta().y() < 0)
	{
		doScaleDec();
	}
	Super::wheelEvent(event);
}
void GLWidget::mousePressEvent(QMouseEvent* event)
{
	auto rp			 = event->windowPos() * qApp->devicePixelRatio();
	auto p			 = rp.toPoint();
	bool changed	 = false;
	auto selectFirst = [p]() { // 找第一个press成功的index,找不到返回-1
		int selectSignleIndex = -1;
		int i				  = 0;
		for (auto comp : gController->comps())
		{
			if (comp->mBillBoard->onPress(p))
			{
				if (selectSignleIndex < 0)
				{
					selectSignleIndex = i;
				}
				break;
			}
			i++;
		}
		return selectSignleIndex;
	};
	if (event->button() == Qt::LeftButton)
	{
		makeCurrent();
		{
			// 鼠标左键
			auto index = selectFirst();
			if (index >= 0 && index < gController->comps().size())
			{
				auto pComp = gController->comps().at(index);
				if (mCtrlPressed)
				{ // 按住Ctrl 多选
					// 切换选中状态
					pComp->mBillBoard->setIsSelected(!pComp->mBillBoard->isSelected());
					changed = true;
				}
				else
				{ // 单选
					for (int i = 0; i < gController->comps().size(); ++i)
					{
						// 仅第一个命中的设置为选中，其它不选
						gController->comps().at(i)->mBillBoard->setIsSelected(i == index);
					}
				}
				changed = true;
			}

			if (!changed)
			{ // 点击空白区域时，全部取消选中
				for (auto comp : gController->comps())
				{
					if (comp->mBillBoard->isSelected())
					{
						comp->mBillBoard->setIsSelected(false);
						changed = true;
					}
				}
				if (!mPressedBlank)
				{
					mPressedBlank	  = true;
					mPressedWindowPos = p;
				}
			}
		}
		doneCurrent();
	}
	else if (event->button() == Qt::RightButton)
	{ // 鼠标右键
		for (auto comp : gController->comps())
		{
			if (comp->mBillBoard->isSelected())
			{
				if (comp->mBillBoard->windowRect().contains(p))
				{
					showMenu(p, comp->mBillBoard->windowRect());
					break;
				}
			}
		}
	}
	if (changed)
	{
		update();
	}
	Super::mousePressEvent(event);
}
void GLWidget::mouseReleaseEvent(QMouseEvent* event)
{
	auto rp		 = event->windowPos() * qApp->devicePixelRatio();
	auto p		 = rp.toPoint();
	bool changed = false;
	makeCurrent();
	{
		for (auto comp : gController->comps())
		{
			if (comp->mBillBoard->onRelease(p))
			{
				changed = true;
			}
		}
		mPressedBlank		 = false;
		mMovedWhenBlankPress = false;

		if (gController->rect()->isVisible())
		{
			gController->rect()->setVisible(false);
			changed = true;
		}
	}
	doneCurrent();
	if (changed)
	{
		update();
	}
	Super::mouseReleaseEvent(event);
}
void GLWidget::mouseMoveEvent(QMouseEvent* event)
{
	auto rp = event->windowPos() * qApp->devicePixelRatio();
	auto p	= rp.toPoint();

	bool changed = false;
	makeCurrent();
	{
		if (mPressedBlank)
		{
			QRect rect(mPressedWindowPos, p);
			for (auto comp : gController->comps())
			{
				bool intersect = rect.intersects(comp->mBillBoard->windowRect());
				if (comp->mBillBoard->isSelected() != intersect)
				{
					comp->mBillBoard->setIsSelected(intersect);
					changed = true;
				}
			}
			mMovedWhenBlankPress = true;
			mMovedWindowPos		 = p;
			if (!gController->rect()->isVisible())
			{
				gController->rect()->setVisible(true);
				gController->rect()->setStart(mPressedWindowPos);
			}
			gController->rect()->setStop(p);

			gController->rect()->updateData();
		}
		else
		{
			for (auto comp : gController->comps())
			{
				if (comp->mBillBoard->onMove(p))
				{
					changed = true;
					break;
				}
			}
		}
	}
	doneCurrent();

	update();
	Super::mouseMoveEvent(event);
}
void GLWidget::mouseDoubleClickEvent(QMouseEvent* event)
{
	auto rp		 = event->windowPos() * qApp->devicePixelRatio();
	auto p		 = rp.toPoint();
	bool changed = false;
	for (auto comp : gController->comps())
	{
		if (comp->mBillBoard->onDoubleClicked(p))
		{
			changed = true;
			break;
		}
	}
	if (changed)
	{
		update();
	}
	Super::mouseDoubleClickEvent(event);
}
void GLWidget::keyPressEvent(QKeyEvent* event)
{
	int step = 5; // 一次移动一个像素
	if (event->modifiers() & Qt::ControlModifier)
	{
		mCtrlPressed = true;
	}

	if (event->key() == Qt::Key_W || event->key() == Qt::Key_Up)
	{
		gController->controlCompTranslate(0, step);
	}
	else if (event->key() == Qt::Key_S || event->key() == Qt::Key_Down)
	{
		gController->controlCompTranslate(0, -step);
	}
	else if (event->key() == Qt::Key_A || event->key() == Qt::Key_Left)
	{
		gController->controlCompTranslate(-step, 0);
	}
	else if (event->key() == Qt::Key_D || event->key() == Qt::Key_Right)
	{
		gController->controlCompTranslate(step, 0);
	}
	Super::keyPressEvent(event);
}
void GLWidget::keyReleaseEvent(QKeyEvent* event)
{
	if (event->modifiers() & Qt::ControlModifier)
	{
		mCtrlPressed = false;
	}
	Super::keyReleaseEvent(event);
}

void GLWidget::timerEvent(QTimerEvent* event)
{
	if (isVisible())
	{
		if (mControlMove)
		{
			QString time = QDateTime::currentDateTime().toString(
				"时间：hh:mm:ss\n222222欢迎来到OpenGL世界。\n333333欢迎来到OpenGL世界。4!4@4#4$4^4&欢迎来到OpenGL世界。\n");
			makeCurrent();
			gController->controlMoveUpdate(time);
			doneCurrent();
		}

		update();
	}
}

void GLWidget::doScaleAdd()
{
	auto s = gController->scale();
	auto t = s + cStep;
	if (isNormal(t))
	{
		mScaleBar->setScaleText(QString("%1%").arg((int)(t * 100)));
		makeCurrent();
		{
			gController->setScale(t);
		}
		doneCurrent();
		update();
	}
}
void GLWidget::doScaleDec()
{
	auto s = gController->scale();
	if (s < 0.25)
	{
		return;
	}
	auto t = s - cStep;
	if (isNormal(t))
	{
		mScaleBar->setScaleText(QString("%1%").arg((int)(t * 100)));
		makeCurrent();
		{
			gController->setScale(t);
		}
		update();
	}
}

void GLWidget::doControlCount(int v)
{
	bool changed = false;
	makeCurrent();
	{
		changed = gController->updateCount(v);
	}
	doneCurrent();
	if (changed)
	{
		update();
	}
}
void GLWidget::startMove()
{
	mControlMove = true;
	update();
}
void GLWidget::stopMove()
{
	mControlMove = false;
	update();
}

void GLWidget::calcFPS()
{
	static QTime time;
	static int	 once = [=]() {
		  time.start();
		  return 0;
	}();
	Q_UNUSED(once)
	static int frame = 0;
	if (frame++ > 30)
	{
		qreal elasped = time.elapsed();
		updateFPS(frame / elasped * 1000);
		time.restart();
		frame = 0;
	}
}
void GLWidget::updateFPS(uint32_t fps)
{
	mFPS = fps;
}
void GLWidget::showFPS()
{
	if (auto pMainWidget = parentWidget())
	{
		pMainWidget->setWindowTitle(QString("TextTexture - FPS: %1").arg(mFPS));
	}
}

void GLWidget::showMenu(QPoint point, const QRect& windowRect)
{
	if (!mMenu)
	{
		mMenu = new QMenu(this);
		mMenu->addAction("Menu 1");
		mMenu->addAction("Menu 2");
		mMenu->addAction("Menu 3");
	}
	//	auto r = windowRect.topRight();
	//	auto x = r.x() / qApp->devicePixelRatio();
	//	auto y = r.y() / qApp->devicePixelRatio();
	// mMenu->setGeometry(x + 6, y + 31, 120, 80);
	mMenu->setGeometry(point.x(), point.y(), 120, 80);
	mMenu->show();
}
